//
// Created by DELL on 2023/3/27.
//
#include <iostream>
#include <memory_resource>
#include <list>

class Tracker : public std::pmr::memory_resource
{
private:
    std::pmr::memory_resource* upstream;  // wrapped memory resource
    std::string prefix{};
public:
    // we wrap the passed or default resource:
    explicit Tracker(std::pmr::memory_resource* us
                     = std::pmr::get_default_resource())
        : upstream{us} {
    }
    explicit Tracker(std::string p,
                     std::pmr::memory_resource* us
                     = std::pmr::get_default_resource())
        : upstream{us}, prefix{std::move(p)} {
    }
private:
    void* do_allocate(size_t bytes, size_t alignment) override {
        void* ret = upstream->allocate(bytes, alignment);
        std::cout << prefix << "allocate " << bytes << " Bytes" << std::endl;
        return ret;
    }
    void do_deallocate(void* ptr, size_t bytes, size_t alignment) override {
        std::cout << prefix << "deallocate " << bytes << " Bytes" << std::endl;
        upstream->deallocate(ptr, bytes, alignment);
    }
    bool do_is_equal(const std::pmr::memory_resource& other) const noexcept
        override {
        // same object?:
        if (this == &other) return true;
        // same type and prefix and equal upstream?:
        auto op = dynamic_cast<const Tracker*>(&other);
        return op != nullptr && op->prefix == prefix
               && upstream->is_equal(other);
    }
};

struct StructA
{
    int64_t a[16]{};
};

int main()
{
    Tracker tracker1{"Allocator: ", std::pmr::new_delete_resource()};
    std::pmr::synchronized_pool_resource poolResource{&tracker1};
    Tracker tracker{"Sync: ", &poolResource};

    {
        std::pmr::list<StructA> list{&tracker};
        list.push_back({});
        auto p = poolResource.allocate(1024);
        for (int i = 0; i < 20; ++i)
        {
            list.push_back({});
        }
        poolResource.deallocate(p, 1024);
        std::cout << "list size: " << list.size() << std::endl;
    }

    std::cout << "-------------------------" << std::endl;
    {
        std::pmr::list<StructA> list{&tracker};
        for (int i = 0; i < 10; ++i)
        {
            list.push_back({});
        }
        std::cout << "list size: " << list.size() << std::endl;
    }


    return 0;
}


